#ifndef _BLOCKQUEUE_HPP_
#define _BLOCKQUEUE_HPP_

#include <iostream>
#include <queue>
#include <functional>
#include <unistd.h>

template < class T >
class Blockqueue
{
    private:
        bool isFull()
        {
            return _cap == _block_queue.size();
        }
        bool isEmpty()
        {
            return _block_queue.empty();
        }
    public:
        Blockqueue(int cap = 5) 
        {
            _cap = cap;
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_product_cond,nullptr);
            pthread_cond_init(&_consume_cond,nullptr);
        }
        ~Blockqueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_product_cond);
            pthread_cond_destroy(&_consume_cond);
        }
        void Enqueue(const T& in)
        {
            // 申请锁。
            pthread_mutex_lock(&_mutex);
            while(isFull())
            {
                // 假设该消费者线程等待。
                ++_productor_wait_num;
                pthread_cond_wait(&_product_cond,&_mutex);
                // 收到信号，取消该消费者线程等待。
                --_productor_wait_num;
            }

            _block_queue.push(in);

            // 生产者弄好了之后，让消费者跑起来处理。
            if(_consumer_wait_num > 0)
            {
                pthread_cond_signal(&_consume_cond);
            }

            pthread_mutex_unlock(&_mutex);
        }
        void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);

            while(isEmpty())
            {
                ++_consumer_wait_num;
                pthread_cond_wait(&_consume_cond,&_mutex);
                --_consumer_wait_num;
            }

            *out = _block_queue.front();
            _block_queue.pop();

            if(_productor_wait_num > 0)
            {
                pthread_cond_signal(&_product_cond);
            }
            
            pthread_mutex_unlock(&_mutex);
        }
    private:
        std::queue<T> _block_queue; // 阻塞队列，是被整体使⽤的！！！ 
        int _cap; // 总上限 
        pthread_mutex_t _mutex; // 保护_block_queue的锁 
        pthread_cond_t _product_cond; // 专⻔给⽣产者提供的条件变量 
        pthread_cond_t _consume_cond; // 专⻔给消费者提供的条件变量 
        int _productor_wait_num;      // 统计等待的生产者线程数量
        int _consumer_wait_num;       // 统计等待的消费者线程数量
};

#endif